﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using BrainTechLLC;
using System.Windows.Threading;
using System.Windows;
using BrainTechLLC.ThreadSafeObjects;
using System.Threading;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;

namespace BrainTechLLC
{
    [Flags]
    public enum RunInitializationResult
    {
        None = 0,
        ContinueTimer = 1,
        StopTimer = 2,
        DidSomething = 4,
        DidntDoAnything = 8,
        DisposeTimer = 16,
    };

    public partial class SimpleTimer
    {
        public bool _reentrancyCheck;
        public Timer _timer;
        protected int _timerInterval;
        public int _doneNothingCount;
        public Func<SimpleTimer, RunInitializationResult> RunInitialization;

        public SimpleTimer(int initialRunDelay, int timerMS, Func<SimpleTimer, RunInitializationResult> runInitialization)
        {
            RunInitialization = runInitialization;
            _timerInterval = timerMS;
            _timer = new Timer(TimerCallbackMethod, this, initialRunDelay, _timerInterval);
        }

        public int TimerInterval
        {
            get { return _timerInterval; }
            set
            {
                if (_timerInterval != value)
                {
                    _timerInterval = value;
                    DisposeTimer();
                    _timer = new Timer(TimerCallbackMethod, this, _timerInterval, _timerInterval);
                }
            }
        }

        public void DisposeTimer()
        {
            if (_timer != null)
            {
                _timer.Dispose();
                _timer = null;
            }
        }

        protected void TimerCallbackMethod(object state)
        {
            var timer = state as SimpleTimer;

            if (timer._reentrancyCheck)
            {
                return;
            }

            timer._reentrancyCheck = true;

            try
            {
                if (timer.RunInitialization != null)
                {
                    RunInitializationResult result = timer.RunInitialization(this);
                    if ((result & RunInitializationResult.DidntDoAnything) == RunInitializationResult.DidntDoAnything)
                    {
                        _doneNothingCount++;
                    }
                    if ((result & RunInitializationResult.DidSomething) == RunInitializationResult.DidSomething)
                    {
                        _doneNothingCount = 0;
                    }
                    if ((result & RunInitializationResult.StopTimer) == RunInitializationResult.StopTimer)
                    {
                        timer._timer.Dispose();
                        timer._timer = null;
                        timer.RunInitialization = null;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            timer._reentrancyCheck = false;
        }
    }

    public class Parallelizer
    {
        public int _threadCount;
        private Action _parallelAction;
        public Thread[] _threads;
        public bool _wantExit;
        public AutoResetEvent _wait = new AutoResetEvent(false);
        public AutoResetEvent _done = new AutoResetEvent(false);

        public void ParallelExecute(Action action1, Action action2)
        {
            ParallelAction = action1;
            action2();
            _done.WaitOne();
        }

        public Action ParallelAction
        {
            set
            {
                if (_parallelAction != null)
                    throw new Exception("Parallel action already scheduled");

                Interlocked.CompareExchange<Action>(ref _parallelAction, value, null);

                _wait.Set();
            }
        }

        public Parallelizer()
        {
            _threadCount = 2;
            _threads = new Thread[_threadCount - 1];

            for (int n = 0; n < _threadCount - 1; n++)
            {
                ThreadStart ts = new ThreadStart(Worker);
                _threads[n] = new Thread(ts)
                {
                    IsBackground = true,
#if NO_SILVERLIGHT
                    //ApartmentState = ApartmentState.MTA,
                    Priority = ThreadPriority.Normal,
#endif
                    Name = "Parallelizer worker thread"

                };
                _threads[n].Start();
            }
        }

        public void Worker()
        {
            while (!_wantExit)
            {
                _wait.WaitOne();

                if (_parallelAction != null)
                {
                    Action action = Interlocked.Exchange<Action>(ref _parallelAction, null);
                    action();
                    _done.Set();
                }
            }
        }
    }

    public static partial class Lookups
    {
        public static ThreadSafeLookupOnDemand<string, Observable> ObservableMethods = new ThreadSafeLookupOnDemand<string, Observable>();
        public static ThreadSafeLookupOnDemand<string, Observable> ObservableProperties = new ThreadSafeLookupOnDemand<string, Observable>();
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable
    {
        [DataMember]
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<object, object, object, object, object>> NotifyObservers;

        public void RaiseNotify(object o1, object o2, object o3, object o4, object o5)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<object, object, object, object, object>(o1, o2, o3, o4, o5));
        }
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable<T1> where T1 : class
    {
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<T1>> NotifyObservers;

        public void RaiseNotify(T1 o1)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<T1>(o1));
        }
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable<T1, T2>
        where T1 : class
        where T2 : class
    {
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<T1, T2>> NotifyObservers;

        public void RaiseNotify(T1 o1, T2 o2)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<T1, T2>(o1, o2));
        }
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable<T1, T2, T3>
        where T1 : class
        where T2 : class
        where T3 : class
    {
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<T1, T2, T3>> NotifyObservers;

        public void RaiseNotify(T1 o1, T2 o2, T3 o3)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<T1, T2, T3>(o1, o2, o3));
        }
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable<T1, T2, T3, T4>
        where T1 : class
        where T2 : class
        where T3 : class
        where T4 : class
    {
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<T1, T2, T3, T4>> NotifyObservers;

        public void RaiseNotify(T1 o1, T2 o2, T3 o3, T4 o4)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<T1, T2, T3, T4>(o1, o2, o3, o4));
        }
    }

#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class Observable<T1, T2, T3, T4, T5>
        where T1 : class
        where T2 : class
        where T3 : class
        where T4 : class
        where T5 : class
    {
        public string ObservableIdentifier { get; set; }

        [field: NonSerialized]
        public event EventHandler<ObjectEventArgs<T1, T2, T3, T4, T5>> NotifyObservers;

        public void RaiseNotify(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5)
        {
            if (NotifyObservers != null)
                NotifyObservers(this, new ObjectEventArgs<T1, T2, T3, T4, T5>(o1, o2, o3, o4, o5));
        }
    }
}
